package com.gamefx.engine1
{
	import com.gamefx.engine1.consts.ActionConst;
	import com.gamefx.engine1.consts.DirectionConst;
	import com.gamefx.engine1.consts.ViewStateConst;
	import com.gamefx.engine1.display.BitmapClip;
	import com.gamefx.engine1.events.GameObjectEvent;
	import com.gamefx.engine1.vo.VAction;
	import com.gamefx.engine1.vo.VEquip;
	import com.gamefx.engine1.vo.VGameObject;
	import com.gamefx.fte.TextBase;
	import com.gamefx.fte.TextConverter;
	import com.gamefx.resource.LoaderManager;
	import com.gamefx.resource.events.LoaderEvent;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.GlowFilter;
	import flash.geom.Matrix;
	import flash.text.engine.ContentElement;
	import flash.text.engine.GroupElement;
	import flash.utils.getTimer;
	
	import mx.utils.ObjectUtil;

	use namespace tm_internal;


	[Event(name = "actionBegin",		type = "com.gamefx.engine1.events.GameObjectEvent")]
	[Event(name = "actionEnd",			type = "com.gamefx.engine1.events.GameObjectEvent")]
	[Event(name = "batchActionEnd",		type = "com.gamefx.engine1.events.GameObjectEvent")]



	/**
	 * 地图上的游戏对象的基类，该类主要实现：<br><br>
	 *
	 * 加载物体外观，默认为"Stand"(即静止)<br>
	 * 物体方向<br>
	 * 动态增加或删除外观层（对人物来说即“换装”）
	 * 动态增加或删除动画（对人物来说即“动作效果”）
	 *
	 * 被点击时会派发GameObjectEvent事件<br>
	 *
	 * @author hzf
	 */
	public class GameObject extends Sprite
	{
		/**
		 * 鼠标高亮滤镜
		 */
		public static const FILTER_MOUSE_OVER:Object = new GlowFilter(0xFFFF66, 0.8, 6, 6, 10, 1);

		/**
		 * 是否暂停播放
		 */
		public var isPaused:Boolean;

		/**
		 * 用于存放裸体躯干、衣着、装备等的图层
		 */
		protected var layerEquips:Sprite;

		/**
		 * 用于存放状态图标等的图层（与layerEquips的区别在于layerStatus不具备“方向”）
		 */
		protected var layerStatus:Sprite;

		/**
		 * 用于显示对象的名称
		 */
		protected var textField:TextBase;

		/**
		 * 播放头时间戳
		 */
		protected var _playheadTime:int;

		/**
		 * 总帧数（Equip总共只有一层BitmapClip时，取BitmapClip.totalframes；多层Equip时，取VAction.frames）
		 */
		protected var _totalFrames:int;
		
		/**
		 * 当前帧
		 */
		protected var _playingFrame:int = -1;



		/**
		 * action_enterFrameHandler是否已开启标记
		 * 当播放非循环动画时，会自动移除action_enterFrameHandler事件侦听
		 */
		tm_internal var isPlaying:Boolean;

		/**
		 * 是否是活动的（GameObjectContainer的显示区域范围内）
		 */
		tm_internal var isActivity:Boolean;

		/**
		 * 坐标是否改变过，用于程序优化检测是否在显示范围内
		 */
		protected var positionChanged:Boolean;

		/**
		 * 提供给enterFrameHandler控制帧率用（优化）
		 */
		protected var lastUpdateTime:int;







		public function GameObject(data:VGameObject = null)
		{
			super();

			_data = data;
			defaultAction = ActionConst.ACTION_MOTION;
			_currentAction = _defaultAction;
			_playheadTime = getTimer();

			mouseChildren = false;

			createChildren();

			addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
			addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
		}


		public function destory():void
		{
			_map = null;

			selfPlay = false;
		}



		//--------------------------------------------------------------------------
		//
		//  Overridden properties
		//
		//--------------------------------------------------------------------------

		/**
		 * 设置位置X
		 * override: 更新碰撞矩形和对象数据
		 * @param value		X位置
		 */
		override public function set x(value:Number):void
		{
			super.x = _data.x = int(value);
			positionChanged = true;
		}

		/**
		 * 设置位置Y
		 * override: 更新碰撞矩形和对象数据
		 * @param value		Y位置
		 */
		override public function set y(value:Number):void
		{
			super.y = _data.y = int(value);
			positionChanged = true;
		}


		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------

		//----------------------------------
		//  data
		//----------------------------------

		protected var _data:VGameObject;

		public function get data():VGameObject
		{
			return _data;
		}


		//----------------------------------
		//  map
		//----------------------------------

		protected var _map:GameContainer;

		public function get map():GameContainer
		{
			return _map;
		}

		public function set map(value:GameContainer):void
		{
			_map = value;

			if (_map != null)
			{
				selfPlay = false;
				positionChanged = true;
				isActivity = false;
			}

			loadEquipsGraph(true);
		}


		//----------------------------------
		//  defaultAction
		//----------------------------------

		/**
		 * 默认的动作
		 * 当其他动作播放完成时，会自动回到该动作
		 */
		protected var _defaultAction:String;

		public function get defaultAction():String
		{
			return _defaultAction;
		}

		public function set defaultAction(value:String):void
		{
			if (!_data.actions.hasOwnProperty(value))
			{
				throw new Error("data.actions has no this action: " + value + ", plese assignment data.actions first.");
			}

			_defaultAction = value;
		}

		//----------------------------------
		//  currentAction
		//----------------------------------

		/**
		 * 当前正在播放的动作
		 */
		protected var _currentAction:String;

		/**
		 * 获取对象当前正在播放的动作
		 *
		 * @return
		 *
		 */
		public function get currentAction():String
		{
			return _currentAction;
		}

		/**
		 * 设置对象的当前动作（播放相应的动画）
		 * 该动作必须为对象已经拥有的动作
		 * 如果所设置的动作已经是对象的当前动作，则该动作会继续播放，而不是重新开始播放
		 *
		 * @param value 动作的标识符
		 *
		 * @see VAction
		 *
		 */
		public function set currentAction(value:String):void
		{
			if (!_data.actions.hasOwnProperty(value))
			{
				throw new Error("data.actions has no this action: " + value + ", plese assignment to data.actions first.");
			}

			if (_currentAction == value)
			{
				return;
			}

			_currentAction = value;
			_playheadTime = getTimer();

			loadEquipsGraph(false);
		}


		//----------------------------------
		//  batchActions
		//----------------------------------

		/**
		 * 连播动作
		 */
		protected var _batchActions:Array;

		/**
		 * 连播动作
		 * @param value 请确保连播中的每一个动作都不是循环动作
		 *
		 */
		public function set batchActions(value:Array):void
		{
			_batchActions = value;
			currentAction = _batchActions.shift();
		}

		//----------------------------------
		//  direction
		//----------------------------------

		/**
		 * 获取当前方向
		 * @return
		 *
		 */
		public function get direction():uint
		{
			return _data.direction;
		}

		/**
		 * 设置当前方向
		 * @param value
		 *
		 */
		public function set direction(value:uint):void
		{
			if (_data.direction == value)
			{
				return;
			}

			var matrix:Matrix = layerEquips.transform.matrix;

			if ((value & DirectionConst.E) && matrix.a != 1)
			{
				matrix.a = matrix.d = 1;
				matrix.tx = -matrix.tx;
				layerEquips.transform.matrix = matrix;
			}

			else if ((value & DirectionConst.W) && matrix.a != -1)
			{
				matrix.a = -1;
				matrix.d = 1;
				matrix.tx = -matrix.tx;
				layerEquips.transform.matrix = matrix;
			}

			_data.direction = value;
		}


		//----------------------------------
		//  isMoving
		//----------------------------------

		/**
		 * 是否正在移动
		 */
		tm_internal function get isMoving():Boolean
		{
			return false;
		}


		//----------------------------------
		//  showTitle
		//----------------------------------

		private var _showTitle:Boolean = true;

		/**
		 * 是否显示对象的名称（标题） 默认为显示
		 */
		public function get showTitle():Boolean
		{
			return _showTitle;
		}

		/**
		 * @private
		 */
		public function set showTitle(value:Boolean):void
		{
			_showTitle = value;
			textField.visible = _showTitle;
		}

		//----------------------------------
		//  titleColor
		//----------------------------------

		private var _titleColor:uint = 0xFFFFFF;

		/**
		 * 标题颜色
		 */
		public function set titleColor(value:uint):void
		{
			if (textField)
			{
				_titleColor = value;
				updateTitle(_data.nickname);
			}
			else
			{
				_titleColor = value;
			}
		}


		//----------------------------------
		//  depth
		//----------------------------------

		/**
		 * 在游戏对象列表中的深度
		 * @return
		 *
		 */
		public function get depth():int
		{
			return int(y);
		}


		//----------------------------------
		//  viewState
		//----------------------------------

		protected var _viewState:uint = ViewStateConst.ALL;

		/**
		 * 显示状态
		 */
		public function set viewState(value:uint):void
		{
			if (value == 0 && _map)
			{
				isActivity = false;
				_map.hideGameObject(this);
			}

			if (_viewState == 0)
			{
				positionChanged = true;
				updateInViewState();
			}

			_viewState = value;

			if ((value & ViewStateConst.EQUIP))
			{
				if (!contains(layerEquips))
				{
					addChild(layerEquips);
				}
			}
			else if (contains(layerEquips))
			{
				removeChild(layerEquips);
			}

			if ((value & ViewStateConst.STATUS))
			{
				if (!contains(layerStatus))
				{
					addChild(layerStatus);
				}
			}
			else if (contains(layerStatus))
			{
				removeChild(layerStatus);
			}

			if ((value & ViewStateConst.TITLE))
			{
				if (!contains(textField))
				{
					addChild(textField);
				}
			}
			else if (contains(textField))
			{
				removeChild(textField);
			}
		}

		public function get viewState():uint
		{
			return _viewState;
		}


		//----------------------------------
		//  自动播放（兼容无GameContainer）
		//----------------------------------

		private var _selfPlay:Boolean;

		public function get selfPlay():Boolean
		{
			return _selfPlay;
		}

		public function set selfPlay(value:Boolean):void
		{
			if (value && !_selfPlay)
			{
				addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}
			else if (!value && _selfPlay)
			{
				removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			}

			_selfPlay = value;
		}


		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------

		//----------------------------------
		//  装备
		//----------------------------------

		/**
		 * 添加装备（重复的KEY的原装备会被移除，即换装）
		 *
		 * @param key 在虚拟装备背包中的索引
		 * @param item 物品
		 */
		public function addEquip(key:String, item:String):void
		{
			_data.equips[key] = item;
			loadEquipsGraph(false);
		}

		/**
		 * 移除装备
		 *
		 * @param key
		 *
		 */
		public function removeEquip(key:String):void
		{
			if (_data.equips.hasOwnProperty(key))
			{
				_data.equips[key] = null;
				delete _data.equips[key];
			}

			loadEquipsGraph(false);
		}


		//----------------------------------
		//  动作
		//----------------------------------

		/**
		 * 添加动作
		 *
		 * @param action
		 *
		 */
		public function addAction(action:VAction):void
		{
			_data.actions[action.key] = action;
		}

		/**
		 * 移除动作
		 *
		 * @param key
		 *
		 */
		public function removeAction(key:String):void
		{
			if (_data.actions.hasOwnProperty(key))
			{
				_data.actions[key] = null;
				delete _data.actions[key];
			}
		}


		//----------------------------------
		//  滤镜
		//----------------------------------

		/**
		 * 添加滤镜
		 * @param value
		 *
		 */
		public function addFilters(value:Array):void
		{
			var filters:Array = this.filters;

			var isExist:Boolean;
			var len:uint = value.length;
			for (var i:uint = 0; i < len; i++)
			{
				isExist = false;
				for (var j:uint = 0; j < filters.length; j++)
				{
					if (ObjectUtil.compare(filters[j], value[i]) == 0)
					{
						isExist = true;
						break;
					}
				}
				if (!isExist)
				{
					filters.push(value[i]);
				}
			}

			this.filters = filters;
		}

		/**
		 * 删除指定的滤镜
		 * @param value
		 *
		 */
		public function removeFilters(value:Array):void
		{
			var filters:Array = this.filters;

			var len:uint = value.length;
			for (var i:uint = 0; i < len; i++)
			{
				for (var j:uint = 0; j < filters.length; j++)
				{
					if (ObjectUtil.compare(filters[j], value[i]) == 0)
					{
						filters.splice(j, 1);
						j--;
					}
				}
			}

			this.filters = filters;
		}

		/**
		 * 创建组件的子对象
		 *
		 */
		protected function createChildren():void
		{
			x = _data.x;
			y = _data.y;

			layerEquips = new Sprite();
			layerEquips.x = -_data.width >> 1;
			layerEquips.y = -_data.equipsBottom;
			addChild(layerEquips);

			layerStatus = new Sprite();
			layerStatus.x = 0;
			addChild(layerStatus);

			textField = new TextBase();
			textField.autoSize = true;

			textField.filters = [new GlowFilter(0x000000, 1, 2, 2, 10)];
			textField.cacheAsBitmap = true;
			addChild(textField);

			calcLayerPosition();
			loadEquipsGraph();

			direction = _data.direction;
		}

		/**
		 * 计算状态栏、标题的Y坐标
		 */
		protected var fixLayerStatusPos:Number = 0;

		protected function calcLayerPosition():void
		{
			layerStatus.y = -_data.equipsBottom + _data.equipsTop + fixLayerStatusPos;
			textField.y = layerStatus.y - 25;
		}

		/**
		 * 更新标题
		 * @param value
		 */
		protected function updateTitle(value:String):void
		{
			if (value.length <= 0)
			{
				return;
			}

			var elements:Vector.<ContentElement> = TextConverter.conver("<p>" + value + "</p>", {fontSize: 13, color: _titleColor, fontName: '宋体'});
			textField.content = (elements.length == 1) ? elements[0] : new GroupElement(elements);
			textField.initialize();
			textField.x = -textField.width >> 1;
		}

		/**
		 * 更新显示状态
		 */
		private function updateInViewState():void
		{
			if (_viewState == 0)
			{
				return;
			}

			if (_map.activityRectChanged || positionChanged)
			{
				if (_map.activityRect.contains(x, y) != isActivity)
				{
					if (isActivity)
					{
						isActivity = false;
						_map.hideGameObject(this);
					}
					else
					{
						isActivity = true;
						_map.showGameObject(this);
					}
				}

				positionChanged = false;
			}
		}

		/**
		 * 精确处理游戏角色鼠标感应
		 * @param hasChildMouseEnabled 是否已经有子对象已经到了鼠标感应
		 *
		 * @return
		 *
		 */
		protected function updateMouseEnabled(hasChildMouseEnabled:Boolean = false):void
		{
			var len:int, i:int;
			var equipGraph:BitmapClip;

			if (hasChildMouseEnabled)
			{
				mouseEnabled = mouseChildren = true;
				return;
			}

			len = layerStatus.numChildren;
			for (i = 0; i < len; i++)
			{
				equipGraph = layerStatus.getChildAt(i) as BitmapClip;

				if (equipGraph && equipGraph.bitmapData && equipGraph.hitTest())
				{
					mouseEnabled = true;
					mouseChildren = false;
					return;
				}
			}

			len = layerEquips.numChildren;
			for (i = 0; i < len; i++)
			{
				equipGraph = layerEquips.getChildAt(i) as BitmapClip;

				if (equipGraph.bitmapData && equipGraph.hitTest())
				{
					mouseEnabled = true;
					mouseChildren = false;
					return;
				}
			}

			mouseEnabled = mouseChildren = false;
		}


		//----------------------------------
		//  载入装备图层
		//----------------------------------
		/**
		 * 载入装备图层
		 * 该方法会自动按照深度进行排序
		 *
		 * @param forceReload 是否强制重新加载JTF true=所有装备均重新加载 false=只加载新增加的装备（默认）
		 * 一般在换装时设为false，切换action时设为true
		 */
		public function loadEquipsGraph(forceReload:Boolean = false):void
		{
			var equipGraph:BitmapClip;
			var isNew:Boolean;

			var equipID:String;
			var itemID:String;
			var equipPartID:String;
			var vEquip:VEquip;

			var arrEquips:Array = [];
			var hasEquips:Object = {};

			var i:int;
			var count:int;
			
			//获取所有部位的装备情况
			for (equipID in _data.equips)
			{
				itemID = String(_data.equips[equipID]);
				for each (vEquip in GameEngine.equipMap[equipID])
				{
					arrEquips.push(vEquip);
					equipPartID = vEquip.key;
					hasEquips[equipPartID] = itemID;
				}
			}

			//去掉没穿在身上的图层
			count = layerEquips.numChildren;
			for (i = 0; i < count; i++)
			{
				equipGraph = layerEquips.getChildAt(i) as BitmapClip;
				if (!hasEquips.hasOwnProperty(equipGraph.name))
				{
					layerEquips.removeChildAt(i);
					i--;
					count--;
				}
			}

			//按顺序显示穿在身上的装备
			arrEquips.sortOn("depth", Array.NUMERIC);
			count = arrEquips.length;
			for (i = 0; i < count; i++)
			{
				equipPartID = VEquip(arrEquips[i]).key;
				equipGraph = layerEquips.getChildByName(equipPartID) as BitmapClip;

				if (equipGraph == null)
				{
					isNew = true;
					equipGraph = new BitmapClip();
					equipGraph.name = equipPartID;
					layerEquips.addChildAt(equipGraph, i);
				}
				else
				{
					layerEquips.setChildIndex(equipGraph, i);
				}

				if (forceReload || isNew)
				{
					equipGraph.load( GameEngine.getResourceUrl(hasEquips[equipPartID], equipPartID, _currentAction), LoaderManager.PRIORITY_MEDIUM);
					isNew = false;
				}
			}
			
			if (count == 1)
			{
				if (equipGraph.data != null && equipGraph.data.ready)
				{
					_totalFrames = equipGraph.getTotalFrames(_currentAction, _data.direction);
				}
				else
				{
					_totalFrames = 0;
					equipGraph.addEventListener(LoaderEvent.PARSE_COMPLETE, equipGraph_parseCompleteHandler, false, 0, true);
				}
			}
			else
			{
				_totalFrames = (_data.actions[_currentAction] as VAction).frames;
			}
			
			isPlaying = true;
		}
		
		private function equipGraph_parseCompleteHandler(event:LoaderEvent):void
		{
			var equipGraph:BitmapClip = event.currentTarget as BitmapClip;
			equipGraph.removeEventListener(LoaderEvent.PARSE_COMPLETE, equipGraph_parseCompleteHandler);
			
			_totalFrames = equipGraph.getTotalFrames(_currentAction, _data.direction);
		}


		/**
		 * 按照当前的播放头、方向绘制所有装备图元
		 */
		private function drawEquips():void
		{
			if (!isActivity)
			{
				return;
			}

			var equipGraph:BitmapClip;

			var count:int = layerEquips.numChildren;
			var i:uint;
			for (i = 0; i < count; i++)
			{
				equipGraph = layerEquips.getChildAt(i) as BitmapClip;

				if (equipGraph != null && equipGraph.data != null && equipGraph.data.ready)
				{
					equipGraph.draw(_playingFrame, _currentAction, DirectionConst.E);
					equipGraph.visible = true;
				}
				else
				{
					equipGraph.visible = false; //防止当拿双刀换剑时，还有一只刀在显示
				}
			}

			count = layerStatus.numChildren;
			for (i = 0; i < count; i++)
			{
				equipGraph = layerStatus.getChildAt(i) as BitmapClip;

				if (equipGraph != null && equipGraph.data != null && equipGraph.data.ready)
				{
					equipGraph.draw(equipGraph.currentFrame >= equipGraph.totalFrames ? 0 : equipGraph.currentFrame + 1);
				}
			}
		}




		//--------------------------------------------------------------------------
		//
		//  Event handlers
		//
		//--------------------------------------------------------------------------

		/**
		 * 播放动作动画
		 * 其原理是根据当前时间与播放头时间戳之间的时间差计算当前帧位置，并更新所有子图元帧位置
		 *
		 * @param event
		 * @param dt
		 */
		public function enterFrameHandler(event:Event = null, dt:uint = 0):void
		{
			if (_map != null)
			{
				updateInViewState();
			}
			else
			{
				isActivity = true;
			}

			if (isActivity)
			{
				if (isPlaying && !isPaused && _totalFrames > 0)
				{
					var action:VAction = _data.actions[_currentAction] as VAction;
					var frame:Number = (getTimer() - _playheadTime) / action.mspf;
					var currentFrame:int = frame % _totalFrames;

					if (_playingFrame != currentFrame)
					{
						_playingFrame = currentFrame;

						if (frame >= _totalFrames)
						{
							dispatchEvent(new GameObjectEvent(GameObjectEvent.ACTION_END));

							if (_batchActions && _batchActions.length < 1)
							{
								_batchActions = null;
								dispatchEvent(new GameObjectEvent(GameObjectEvent.BATCH_ACTION_END));
							}

							if (_batchActions && _batchActions.length > 0)
							{
								_playheadTime = getTimer();
								currentAction = _batchActions.shift();
							}
							else if (action.loop)
							{
								_playheadTime = getTimer() - (frame - _totalFrames) * action.mspf;
							}
							else
							{
								isPlaying = false;

								if (_currentAction != _defaultAction)
								{
									currentAction = _defaultAction;
								}
								else
								{
									_playingFrame = _totalFrames - 1;
								}
								_playingFrame = _totalFrames - 1;
							}
						}
						drawEquips();
					}
				}

				updateMouseEnabled();
			}
		}


		private function mouseOverHandler(event:MouseEvent):void
		{
			addFilters([FILTER_MOUSE_OVER]);
			event.stopPropagation();
		}

		private function mouseOutHandler(event:MouseEvent):void
		{
			removeFilters([FILTER_MOUSE_OVER]);
		}

	}
}
